#include "catch.hpp"
#include "Lexer.h"
#include "Parser.h"
#include "PrintVisitor.h"
#include <iostream>

using namespace C100;

TEST_CASE("C100_lexer", "lexer 5+ a+ (1-3)*4/2;") {
    const char *code = "5+ a1001+ (1-3)*4/2;";
    Lexer lexer(code);
    lexer.getNextToken();
    REQUIRE("5" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE("+" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE("a1001" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE("+" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE("(" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE("1" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE("-" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE("3" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE(")" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE("*" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE("4" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE("/" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE("2" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE(";" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE(TokenKind::Eof == lexer.currentToken->kind);
}
TEST_CASE("C100_lexer1", "lexer a=3;") {
    const char *code = "a=3;";
    Lexer lexer(code);
    lexer.getNextToken();
    REQUIRE("a" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE("=" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE("3" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE(";" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE(TokenKind::Eof == lexer.currentToken->kind);
}

TEST_CASE("C100_lexer2", "lexer a==3;a!=3;a>3;a>=3;a<3;a<=3;") {
    const char *code = "a==3;a!=3;a>3;a>=3;a<3;a<=3;";
    Lexer lexer(code);
    lexer.getNextToken();
    REQUIRE("a" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE("==" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE("3" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE(";" == lexer.currentToken->content);
    lexer.getNextToken();

    REQUIRE("a" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE("!=" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE("3" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE(";" == lexer.currentToken->content);
    lexer.getNextToken();

    REQUIRE("a" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE(">" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE("3" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE(";" == lexer.currentToken->content);
    lexer.getNextToken();

    REQUIRE("a" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE(">=" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE("3" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE(";" == lexer.currentToken->content);
    lexer.getNextToken();

    REQUIRE("a" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE("<" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE("3" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE(";" == lexer.currentToken->content);
    lexer.getNextToken();

    REQUIRE("a" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE("<=" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE("3" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE(";" == lexer.currentToken->content);
    lexer.getNextToken();
    REQUIRE(TokenKind::Eof == lexer.currentToken->kind);
}

TEST_CASE("C100_lexer3", "lexer a=3;if (a != 3) a = 3;else a = a * a;") {
    const char *code = "a=3;if (a != 3) a = 3;else a = a * a;";
    Lexer lexer(code);
    std::vector<std::string> res = {
            "a","=","3",";","if","(","a","!=","3",")","a","=","3",";","else","a","=","a","*","a",";","\0"
    };
    int i = 0;
    do{
        lexer.getNextToken();
        REQUIRE(res[i++] == lexer.currentToken->content);
    } while (lexer.currentToken->kind != TokenKind::Eof);
}

TEST_CASE("C100_parser", "parser1") {
    const char *code = "a = 3;a+ 5+ (1-3)*4/2;a+2;";
    Lexer lexer(code);
    lexer.getNextToken();
    Parser parser(lexer);
    auto root = parser.parse();
    PrintVisitor visitor;
    root->accept(&visitor);
    REQUIRE("a=3;a+5+1-3*4/2;a+2;" == visitor.content);
}

TEST_CASE("C100_parser1", "parser2") {
    const char *code = "a==3;a!=3;a>3;a>=3;a<3;a<=3;";
    Lexer lexer(code);
    lexer.getNextToken();
    Parser parser(lexer);
    auto root = parser.parse();
    PrintVisitor visitor;
    root->accept(&visitor);
    REQUIRE("a==3;a!=3;a>3;a>=3;a<3;a<=3;" == visitor.content);
}

TEST_CASE("C100_parser3", "parser3") {
    const char *code = "a=3;if (a != 3) a = 3;else a = a * a;";
    Lexer lexer(code);
    lexer.getNextToken();
    Parser parser(lexer);
    auto root = parser.parse();
    PrintVisitor visitor;
    root->accept(&visitor);
    REQUIRE("a=3;if(a!=3)a=3;elsea=a*a;" == visitor.content);
}

TEST_CASE("C100_parser4", "parser4") {
    const char *code = "a=3;if (a != 3) {a = 3;}else a = a * a;";
    Lexer lexer(code);
    lexer.getNextToken();
    Parser parser(lexer);
    auto root = parser.parse();
    PrintVisitor visitor;
    root->accept(&visitor);
    std::cout << visitor.content<<std::endl;
    REQUIRE("a=3;if(a!=3){a=3;}elsea=a*a;" == visitor.content);
}